/*
 *      Author: Honrun
 */
#include "stdint.h"
#include "stdio.h"
#include "gd32f10x.h"

#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

#include "DevicesQueue.h"
#include "DevicesTime.h"
#include "DevicesSoftTimer.h"
#include "userTask.h"
#include "DevicesKey.h"


KeyTypeDef g_typeKeyData;
SoftTimerTypeDef g_typeSoftTimerKeyHanle = {0};


void vSoftTimerKeyCallbackFunction(void *pvHandle)
{
    (void)pvHandle;

    /* 运行状态机，以检测是否有按键动作 */
    if(enumKeyStateMachine(&g_typeKeyData) != keyNormal)
    {
        /* 把按键值push到FIFO */
        enumQueuePushDatas(&g_TypeQueueKeyInput, &g_typeKeyData, sizeof(KeyTypeDef));

        /* 给出信号量，以启动任务执行 */
        xTaskNotifyGive(g_TaskKeyHand);
    }
}

void vKeyInit(void)
{
    /* enable the GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOD);

    gpio_bit_set(GPIOD, GPIO_PIN_0);
    gpio_bit_set(GPIOD, GPIO_PIN_1);

    /* configure key pin as input */
    gpio_init(GPIOD, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_0);
    gpio_init(GPIOD, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_1);

    g_typeKeyData.uiKeyValueGet = uiKeyValueGet;

    /* 软件定时器周期调用 */
    cSoftTimerCreateMs(&g_typeSoftTimerKeyHanle, 20, softTimerOpen | softTimerCircular, vSoftTimerKeyCallbackFunction);
}

/*
Return Value:   按键组合序号（头文件里有定义）
Parameters:     void
Description:    读取当前按键状态
*/
uint32_t uiKeyValueGet(void)
{
    uint32_t Key = KEY_HOME | KEY_POWER;
    uint8_t i = 0;

    for(i = 0; i < 8; ++i)
    {
        if(RESET != gpio_input_bit_get(GPIOD, GPIO_PIN_0))
            Key &= ~KEY_HOME;
        if(RESET != gpio_input_bit_get(GPIOD, GPIO_PIN_1))
            Key &= ~KEY_POWER;
    }

    return Key;
}

/*
 * Return:      void
 * Parameters:  void
 * Description: 按键状态机信息获取
 */
KeyStateEnum enumKeyStateMachine(KeyTypeDef *ptypeKeyMachine)
{
    uint32_t uiNewValue = 0, uiTimeNow = 0;
    KeyStateEnum enumState;

    if(ptypeKeyMachine == NULL)
        return keyNormal;

    /* 键值获取 */
    if(((uiNewValue = ptypeKeyMachine->uiKeyValueGet()) != 0) || (ptypeKeyMachine->valueOld != 0))
    {
        /* 按键状态判断 */
        enumState = enumKeyStateGet(uiNewValue, ptypeKeyMachine->valueOld);

        uiTimeNow = lTimeGetStamp() / 1000;

        /* 按键状态转换 */
        switch(enumState)
        {
            /* 记录按键按下时间、按下总键值，松开按键键值清零 */
            case keyAdd:
                ptypeKeyMachine->valuePress = uiNewValue;
                ptypeKeyMachine->timePress = uiTimeNow;
                ptypeKeyMachine->valueLoosen = 0;
                ptypeKeyMachine->state = keyNormal;
                break;

            /* 记录按键松开时间、松开总键值 */
            case keyCut:
                ptypeKeyMachine->valueLoosen |= ptypeKeyMachine->valueOld & (~uiNewValue);
                ptypeKeyMachine->timeLoosen = uiTimeNow;
                ptypeKeyMachine->valueOld = uiNewValue;
                ptypeKeyMachine->state |= keyCut;
                return ptypeKeyMachine->state;

            /* 记录按键按下时间、按下总键值、松开时间、松开总键值 */
            case keyAddAndCut:
                ptypeKeyMachine->valuePress = uiNewValue;
                ptypeKeyMachine->timePress = uiTimeNow;
                ptypeKeyMachine->valueLoosen |= ptypeKeyMachine->valueOld & (~uiNewValue);
                ptypeKeyMachine->timeLoosen = uiTimeNow;
                break;

            case keyEqual:
                return enumKeyTimeStateGet(ptypeKeyMachine);

            default: break;
        }

        /* 设定新键值 */
        ptypeKeyMachine->valueOld = uiNewValue;
    }

    return keyNormal;
}

/*
 * Return:      按键状态
 * Parameters:  Value_new:新按键键值; Value_old:旧按键键值;
 * Description: 按键状态获取
 */
KeyStateEnum enumKeyStateGet(uint32_t uiNewValue, uint32_t uiOldValue)
{
    if(uiNewValue == uiOldValue)                        /* 当前按键值与上次按键值相同 */
        return keyEqual;
    else if((uiNewValue & uiOldValue) == uiOldValue)    /* 当前按键值在上次按键值基础上增加了新按键 */
        return keyAdd;
    else if((uiNewValue | uiOldValue) == uiOldValue)    /* 当前按键值在上次按键值基础上减少了旧按键 */
        return keyCut;
    else                                                /* 当前按键值在上次按键值基础上即减少了旧按键又增加了新按键 */
        return keyAddAndCut;
}

/*
 * Return:      按键状态
 * Parameters:  Value_new:新按键键值; Value_old:旧按键键值;
 * Description: 按键状态获取
 */
KeyStateEnum enumKeyTimeStateGet(KeyTypeDef *ptypeKeyMachine)
{
    int32_t lTimeNow = 0;

    lTimeNow = lTimeGetStamp() / 1000;

    switch(ptypeKeyMachine->state)
    {
        case keyNormal:
            if((lTimeNow - ptypeKeyMachine->timePress) >= KEY_SHORT_TIME)
            {
                ptypeKeyMachine->state = keyShort;
                return keyShort;
            }
            break;

        case keyShort:
            if((lTimeNow - ptypeKeyMachine->timePress) >= KEY_LONG_TIME)
            {
                ptypeKeyMachine->state = keyLong;
                return keyLong;
            }
            break;

        case keyLong:
            if((lTimeNow - ptypeKeyMachine->timePress) >= KEY_CONTINUE_TIME)
            {
                ptypeKeyMachine->state = keyContinuous;
                ptypeKeyMachine->timeContinuous = lTimeNow;
            }
            break;

        case keyContinuous:
            if((lTimeNow - ptypeKeyMachine->timeContinuous) >= KEY_CONTINUE_INTERVAL_TIME)
            {
                ptypeKeyMachine->timeContinuous = lTimeNow;
                return keyContinuous;
            }
            break;

        default : break;
    }

    return keyNormal;
}
